﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace UPA
{
    [CreateAssetMenu(menuName = "流程自动化/组配置")]
    public class ProcessActionGroup : ScriptableObject,ISerializationCallbackReceiver
    {
        [SerializeField]
        private List<ProcessActionArgumentSetting> settings = new();
        [SerializeField]
        private List<ProcessActionUnit> actionUnits = new();
        
        public List<ProcessActionArgumentSetting> Settings => settings;
        public List<ProcessActionUnit> ActionUnits => actionUnits;

        public ProcessActionArgumentSetting CurSetting
        {
            get
            {
                if (CurSelectSettingIndex >= settings.Count)
                {
                    CurSelectSettingIndex = 0;
                }

                return Settings[CurSelectSettingIndex];
            }
        }

        private int _curSelectSettingIndex;

        public int CurSelectSettingIndex
        {
            get => _curSelectSettingIndex;
            set
            {
                var old = _curSelectSettingIndex;
                _curSelectSettingIndex = Mathf.Clamp(value, 0, Math.Max(0,settings.Count - 1));
                if (old != _curSelectSettingIndex)
                {
                    OnSettingChanged();
                }
            }
        }

        public void InitDefaultSetting()
        {
            if (settings.Count == 0)
            {
                AddNewSetting();
            }
        }

        public void AddAction(Type type)
        {
            var action = Activator.CreateInstance(type) as ProcessAction;
            if (action == null)
            {
                Debug.LogError($"{type.FullName} 没有继承自 {nameof(ProcessAction)} 类型");
                return;
            }
            
            actionUnits.Add(new ProcessActionUnit(action));
            foreach (var setting in settings)
            {
                AppendArgument(setting,action);
            }
            action.SetArgument(CurSetting.Arguments[^1]);
        }

        public void SwapAction(int firstIndex, int secondIndex)
        {
            if (firstIndex < 0 || firstIndex >= actionUnits.Count || secondIndex < 0 || secondIndex >= actionUnits.Count)
            {
                return;
            }
            
            (actionUnits[firstIndex], actionUnits[secondIndex]) = (actionUnits[secondIndex], actionUnits[firstIndex]);
            foreach (var setting in settings)
            {
                (setting.Arguments[firstIndex], setting.Arguments[secondIndex]) = (setting.Arguments[secondIndex], setting.Arguments[firstIndex]);
            }
        }

        public void RemoveAction(int index)
        {
            if (index < 0 || index >= actionUnits.Count)
            {
                return;
            }
            
            actionUnits.RemoveAt(index);
            foreach (var setting in settings)
            {
                setting.Arguments.RemoveAt(index);
            }
        }

        public void AddNewSetting()
        {
            var newSetting = new ProcessActionArgumentSetting();
            foreach (var unit in actionUnits)
            {
                AppendArgument(newSetting,unit.Action);
            }
            AddNewSetting(newSetting);
        }

        public void AddNewSetting(ProcessActionArgumentSetting newSetting)
        {
            int index = 0;
            foreach (var setting in settings)
            {
                if (setting.Name.StartsWith(newSetting.Name))
                {
                    index++;
                }
            }
            if (index > 0)
            {
                newSetting.Name += $"_{index}";
            }
            settings.Add(newSetting);
        }

        public void RemoveSetting(int index)
        {
            settings.RemoveAt(index);
        }

        private void AppendArgument(ProcessActionArgumentSetting setting, ProcessAction action)
        {
            if (action == null)
            {
                setting.Arguments.Add(null);
            }
            else if (action.RequiredArgument == null)
            {
                setting.Arguments.Add(null);
            }
            else
            {
                setting.Arguments.Add(Activator.CreateInstance(action.RequiredArgument) as ProcessActionArgument);
            }
        }
        
        private void OnSettingChanged()
        {
            for (int i = 0; i < actionUnits.Count; i++)
            {
                actionUnits[i].Action.SetArgument(CurSetting.Arguments[i]);
            }
        }

        public void OnBeforeSerialize() { }

        public void OnAfterDeserialize()
        {
            InitDefaultSetting();

            for (int i = 0; i < actionUnits.Count; i++)
            {
                actionUnits[i].Action?.SetArgument(CurSetting.Arguments[i]);
            }
        }
    }
}